package dryven.view.engine;

import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;

import dryven.view.ViewDataDictionary;
import dryven.view.ViewEngine;
import dryven.view.engine.expression.nodelisters.DefaultNodeListerFactory;
import dryven.view.engine.expression.nodelisters.ExpressionNodeFactory;
import dryven.view.engine.parser.CompilationException;
import dryven.view.engine.parser.CompiledViewFile;
import dryven.view.engine.parser.ViewFileCompiler;

public class DryvenViewEngine implements ViewEngine {

	private Iterable<String> _viewPackages;
	private Iterable<String> _importedPackages;
	public DryvenViewEngine(Iterable<String> viewPackages, Iterable<String> importedPackages) {
		super();
		_viewPackages = viewPackages;
		_importedPackages = importedPackages;
	}

	@Override
	public void renderView(String viewName, Writer out,
			ViewDataDictionary viewData) {
		if(!viewName.startsWith("/")) {
			viewName = "/"+viewName;
		}
		InputStream pageSource = findPageSource(viewName);
		if(pageSource==null) {
			throw new RuntimeException(String.format("Could not find view file '%s'", viewName));
		}
		renderView(pageSource, out, viewData);
	}

	private InputStream findPageSource(String viewName) {
		InputStream pageSource = null;
		for (String packageName : _viewPackages) {
			String packageDir = "/"+packageName.replace('.', '/');
			String fileName = packageDir+viewName+".xml";
			pageSource = getClass().getResourceAsStream(fileName);
			if(pageSource==null) {
				fileName = packageDir+viewName+".dry";
				pageSource = getClass().getResourceAsStream(fileName);
			}
			if(pageSource!=null) {
				break;
			}
		}
		return pageSource;
	}

	@Override
	public void renderView(InputStream viewSource, Writer out,
			ViewDataDictionary viewData) {
		ExpressionNodeFactory expressionFactory = new DefaultNodeListerFactory();
		ViewFileCompiler compiler = new ViewFileCompiler(viewSource, expressionFactory, _importedPackages);
		CompiledViewFile compiledPage;
		try {
			compiledPage = compiler.compile();
		} catch (CompilationException e1) {
			throw new RuntimeException(e1);
		}
		try {
			compiledPage.render(viewData, out);
		} catch (IOException e) {
			throw new RuntimeException("Error reading view page", e);
		}
	}
}
